//
// Created by denglibin on 2021/8/13.
//如果你定义了一个窗口重画事件处理函数，则必须在这个处理函数中产生一个wxPaintDC设
//备上下文（即使你根本不使用它），并且使用它来进行你需要的绘画动作。产生这个对象将告诉
//wxWidgets的窗口体系这个窗口的需要重画的区域已经被重画了，这样窗口系统就不会重复的发送重
//画消息给这个窗口了。
//在重画事件中，你还可以调用wxWindow::GetUpdateRegion函数来获得需要重
//画的区域，或者使用wxWindow::IsExposed函数来判断某个点或者某个矩形区域是否需要重画，然后
//优化代码使得仅在这个范围内的内容被重画，虽然在重画事件中创建的wxPaintDC设备上下文会自动
//将自己限制在需要重画的区域内，不过你自己知道需要重画的区域的话，可以对代码进行相应的优
//化.
//重画事件是由于用户和窗口系统的交互造成的，但是它也可以通过调用wxWindow::Refresh
//和wxWindow::RefreshRect函数手动产生。如果你准确的知道窗口的哪个部分需要重画，你可以指
//定只重画那一部分区域以便尽可能的减少闪烁。这样作的一个问题是，并不能保证窗口在调用
//Refresh函数以后会马上重画。如果你真的需要立刻调用你的重画事件处理函数，比如说你在进
//行一个很耗时的计算，需要即时显示一些进度，你可以在调用Refresh或者RefreshRect以后调用
//wxWindow::Update函数
//wxBufferedPaintDC是wxPaintDC的双缓冲区版本。只需要简单的将重绘事件处理函数中的wxPaintDC换成wxBufferedPaintDC就可以了，
// 它会首先将所有的图片画在一个内存位图上，然后在自
//己被释放的时候一次性将其画在窗口上以减小闪烁。
#include <wx/app.h>
#include <wx/wx.h>
#include <wx/wxprec.h>
#include <string>
#include <wx/dcbuffer.h>
using namespace std;
class PaintDcFrame : public wxFrame
{
private:
    //声明事件表
    DECLARE_EVENT_TABLE();


    void OnEraseBackground(wxEraseEvent & event){

    }
    /**
     * 绘图
     * @param event
     */
    void OnPaint(wxPaintEvent & event){
        //wxPaintDC dc(this);
        wxBufferedPaintDC dc(this);
        PrepareDC(dc);

        PaintBackground(dc);
        dc.SetPen(*wxBLACK_PEN);
        dc.SetBrush(*wxRED_BRUSH);
        dc.DrawEllipse(wxPoint(0, 0), wxSize(50, 50));
        dc.SetBrush(wxNullBrush);//清除画刷颜色
        dc.SetPen(wxNullPen);//清除画笔颜色

    }

    // / 绘制背景
    void PaintBackground ( wxDC & dc )
    {
        //wxColour backgroundColour = GetBackgroundColour();
        wxColour  backgroundColour(200, 100, 10);
        if (! backgroundColour.Ok ()){
            backgroundColour = wxSystemSettings :: GetColour ( wxSYS_COLOUR_3DFACE );
        }
        dc.SetBrush (wxBrush(backgroundColour));
        dc.SetPen ( wxPen( backgroundColour , 1));
        wxRect windowRect ( wxPoint (0 , 0) , GetClientSize ());
//我们需要平移当前客户区矩形的座标
//以便将其转换成相对于整个滚动窗口而不是当前窗口的座标
//因为在前面我们已经对设备上下文进行了
//的动作
        dc.DrawRectangle ( windowRect );
    }
    /**
     * 初始化frame
     */
    void initFrame(){
        //默认情况下，当窗口大小改变时，只有那些需要重画的地方才会被更新，指定wx-
        //FULL REPAINT ON RESIZE窗口类型可以覆盖这种默认情况以使得整个窗口都被刷新
        wxFULL_REPAINT_ON_RESIZE;

        //wxImage::AddHandler(new wxJPEGHandler);
        //wxImage::AddHandler(new wxPNGHandler);
        //设置窗口位置
        wxPoint position;
        position.x = 300;
        position.y = 300;
        SetPosition(position);
        //设置背景色
        wxColour backGroundColor(0,100,0);
        this->SetBackgroundColour(backGroundColor);
        //设置宽高
        this->m_minWidth = 800;
        this->m_minHeight = 600;
    }

public:
    explicit PaintDcFrame(wxString & title):wxFrame(nullptr, wxID_ANY, title)
    {
        this->initFrame();
    }
    ~PaintDcFrame() override{
        cout << "~PaintDcFrame" << endl;
    };

};

//事件和函数绑定
wxBEGIN_EVENT_TABLE(PaintDcFrame, wxFrame)
    EVT_PAINT(PaintDcFrame::OnPaint)
    EVT_ERASE_BACKGROUND( PaintDcFrame :: OnEraseBackground )
wxEND_EVENT_TABLE()

/**
 * app
 */
class PaintDcApp:public wxApp
{
    bool OnInit()override
    {
        wxString title = wxT("PaintDc绘制");
        //  wxFrame * frame = new wxFrame(NULL, wxID_ANY, "第一个窗体");
        auto * frame = new PaintDcFrame(title);
        frame->Show();
        cout << "OnInit"<< endl;
        return true;
    }
};


// 有了这一行就可以使用 OurApp& wxGetApp了()
DECLARE_APP(PaintDcApp)
//告诉主应用程序是哪个类wxWidgets（启动）
//IMPLEMENT_APP(PaintDcApp)